package element;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import springiesSimulator.Assembly;
import util.Vector;


/**
 * @author Robert C. Duvall modified by Mark Hoffman and Mark Govea
 */
public class Mass implements RenderableObject {
    private static final int DEFAULT_SIZE = 16;
    // state
    private Point2D myCenter;
    private Vector myVelocity;
    private Dimension mySize;
    private int myID;
    private double myMass;
    private Vector myAcceleration;
    private Assembly myAssembly;

    /**
     * @param assembly the set of masses/springs this is associated
     * @param id identifier for the mass
     * @param x horizontal location of the mass
     * @param y vertical location of the mass
     * @param mass amount of inertia of the object
     */
    public Mass (Assembly assembly, int id, double x, double y, double mass) {
        myAssembly = assembly;
        setMyAcceleration(new Vector());
        setMyMass(mass);
        setMyID(id);
        setCenter(x, y);
        setVelocity(0, 0);
        setMySize(new Dimension(DEFAULT_SIZE, DEFAULT_SIZE));
    }

    @Override
    public void paint (Graphics2D pen) {
        pen.setColor(Color.BLACK);
        pen.fillOval(getLeft(), getTop(), getSize().width, getSize().height);
    }

    @Override
    public void update (Assembly assembly, double dt) {
        assembly.getMyEnvironmentManager().applyEnvironmentalForces(this);
        // convert force back into Mover's velocity
        getVelocity().sum(getMyAcceleration());
        getMyAcceleration().reset();
        // move mass by velocity
        getCenter().setLocation(
                getCenter().getX() + getVelocity().getXChange() * dt,
                getCenter().getY() + getVelocity().getYChange() * dt);
        // check if out of bounds
        assembly.getMyEnvironmentManager().checkBounce(this);
    }

    /**
     * @param f
     *        force to be applied to this mass
     */
    public void applyForce (Vector f) {
        f.scale(1.0 / getMyMass());
        getMyAcceleration().sum(f);
    }

    /**
     * @param id used to match this mass
     */
    public boolean matchByID (int id) {
        return getMyID() == id;
    }

    // Instance variables getters and setters

    /**
     * Returns shape's center.
     */
    public Point2D getCenter () {
        return myCenter;
    }

    /**
     * Resets shape's center.
     *
     * @param x set horizontal coordinate of mass's center
     * @param y set vertical coordinate of mass's center
     */
    public void setCenter (double x, double y) {
        myCenter = new Point2D.Double(x, y);
    }

    /**
     * Returns shape's velocity.
     */
    public Vector getVelocity () {
        return myVelocity;
    }

    /**
     * Resets shape's velocity.
     *
     * @param direction heading of the force
     * @param magnitude strength of the force
     */
    public void setVelocity (double direction, double magnitude) {
        myVelocity = new Vector(direction, magnitude);
    }

    /**
     * @return the size of the mass
     */
    public Dimension getSize () {
        return mySize;
    }

    private void setMySize (Dimension size) {
        mySize = size;
    }

    /**
     * @return the mass's ID
     */
    public int getMyID () {
        return myID;
    }

    private void setMyID (int id) {
        myID = id;
    }

    /**
     * @return the mass of the object
     */
    public double getMyMass () {
        return myMass;
    }

    private void setMyMass (double mass) {
        myMass = mass;
    }

    /**
     * @return current acceleration of the mass (direction and magnitude)
     */
    public Vector getMyAcceleration () {
        return myAcceleration;
    }

    private void setMyAcceleration (Vector acceleration) {
        myAcceleration = acceleration;
    }

    // Variants of existing getters and setters

    /**
     * Returns shape's left-most coordinate.
     */
    public int getLeft () {
        return (int) (getCenter().getX() - getSize().width / 2);
    }

    /**
     * Returns shape's top-most coordinate.
     */
    public int getTop () {
        return (int) (getCenter().getY() - getSize().height / 2);
    }

    /**
     * Returns shape's right-most coordinate.
     */
    public int getRight () {
        return (int) (getCenter().getX() + getSize().width / 2);
    }

    /**
     * Reports shape's bottom-most coordinate.
     *
     * @return bottom-most coordinate
     */
    public int getBottom () {
        return (int) (getCenter().getY() + getSize().height / 2);
    }

    /**
     *
     * @return this assembly
     */
    public Assembly getMyAssembly () {
        return myAssembly;
    }
}
